package org.jeecg.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.TenantConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.mapper.SysTenantMapper;
import org.jeecg.modules.system.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@Slf4j
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements ISysTenantService {

    @Autowired
    ISysPermissionService sysPermissionService;

    @Autowired
    ISysUserService userService;

    @Autowired
    ISysRoleService sysRoleService;

    @Autowired
    ISysUserRoleService sysUserRoleService;

    @Autowired
    ISysRolePermissionService sysRolePermissionService;

    @Autowired
    private BaseCommonService baseCommonService;

    @Override
    public List<SysTenant> queryEffectiveTenant(Collection<Integer> idList) {
        LambdaQueryWrapper<SysTenant> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysTenant::getId, idList);
        queryWrapper.eq(SysTenant::getStatus, Integer.valueOf(CommonConstant.STATUS_1));
        //此处查询忽略时间条件
        return super.list(queryWrapper);
    }

    @Override
    public Long countUserLinkTenant(String id) {
        LambdaQueryWrapper<SysUser> userQueryWrapper = new LambdaQueryWrapper<>();
        userQueryWrapper.eq(SysUser::getRelTenantIds, id);
        userQueryWrapper.or().likeLeft(SysUser::getRelTenantIds, "," + id);
        userQueryWrapper.or().likeRight(SysUser::getRelTenantIds, id + ",");
        userQueryWrapper.or().like(SysUser::getRelTenantIds, "," + id + ",");
        // 查找出已被关联的用户数量
        return userService.count(userQueryWrapper);
    }

    @Override
    public boolean removeTenantById(String id) {
        // 查找出已被关联的用户数量
        Long userCount = this.countUserLinkTenant(id);
        if (userCount > 0) {
            throw new JeecgBootException("该租户已被引用，无法删除！");
        }
        return this.deleteById(Integer.parseInt(id));
    }

    /**
     * 批量删除租户
     * @param ids
     * @return
     */
    @Override
    public Result<?> deleteBatch(String ids) {
        Result<?> result = new Result<>();
        String[] ls = ids.split(",");
        // 过滤掉已被引用的租户
        List<Integer> idList = new ArrayList<>();
        for (String id : ls) {
            Long userCount = this.countUserLinkTenant(id);
            if (userCount == 0) {
                idList.add(Integer.parseInt(id));
            }
        }
        if (idList.size() > 0) {
            for(Integer id: idList){
                this.deleteById(id);
            }
            if (ls.length == idList.size()) {
                result.success("删除成功！");
            } else {
                result.success("部分删除成功！（被引用的租户无法删除）");
            }
        }else  {
            result.error500("选择的租户都已被引用，无法删除！");
        }
        return result;
    }

    /**
     * 删除租户及相关数据
     * @param id
     * @return
     */
    private boolean deleteById(Integer id){
        LambdaQueryWrapper<SysUserRole> lambdaQueryWrapperUserRole=new LambdaQueryWrapper<>();
        lambdaQueryWrapperUserRole.inSql(SysUserRole::getRoleId,"select id from sys_role where tenant_id="+id);
        sysUserRoleService.remove(lambdaQueryWrapperUserRole);

        LambdaQueryWrapper<SysRolePermission> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.inSql(SysRolePermission::getRoleId,"select id from sys_role where tenant_id="+id);
        sysRolePermissionService.remove(lambdaQueryWrapper);

        sysPermissionService.deleteByTenantId(id);

        sysRoleService.deleteByTenantId(id);

        return super.removeById(id);
    }

    private List<SysPermission> getPermissionList(){
        LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
        query.eq(SysPermission::getTenantId, TenantConstant.MATER_TENANT_ID);
        //创建其他租户的时候，默认给租户授权的默认菜单列表
        query.in(SysPermission::getId, Arrays.asList(
                "1438108176273760258",//Dashboard
                "9502685863ab87f0ad1134142788a385",//首页
                "d7d6e2e4e2934f2c9385a623fd98c6f3",//系统管理
                "3f915b2769fc80648e92d04e84ca059d",//用户管理
                "190c2b43bec6a5f7a4194a85db67d96a",//角色管理
                "45c966826eeff4c99b8f8ebfe74511fc",//部门管理
                "5c2f42277948043026b7a14692456828",//我的部门
                "1438469604861403137",//职务管理
                "1438782851980210178",//通知公告
                "1455735714507472898",//通讯录
                "1443390062919208961",//消息中心
                "1443391584864358402",//消息模板
                "1439542701152575489"//消息模板
                ));
        List<SysPermission> ls = sysPermissionService.list(query);

        return ls;
    }

    @Override
    @Transactional
    public void saveSysTenant(SysTenant sysTenant) {
        this.save(sysTenant);
        int tenantId = sysTenant.getId();
        List<SysPermission> ls = getPermissionList();
        Collection<String> menuIds = setPermissionTenant(ls, tenantId);
        sysPermissionService.saveBatch(ls);

        // 添加admin角色
        SysRole role = new SysRole();
        role.setRoleCode(CommonConstant.ROLE_CODE_ADMIN);
        role.setRoleName("管理员");
        role.setTenantId(tenantId);
        sysRoleService.save(role);

        // 添加角色 菜单关系
        List<SysRolePermission> list = new ArrayList<>();
        for(String menuId: menuIds){
            SysRolePermission sp = new SysRolePermission();
            sp.setPermissionId(menuId);
            sp.setRoleId(role.getId());
            list.add(sp);
        }
        sysRolePermissionService.saveBatch(list);

        this.addTenantUser(role.getId(),tenantId);

    }

    /**
     * 新增租户的用户
     * @param roleId
     * @param tenantId
     */
    private void addTenantUser(String roleId,Integer tenantId){
        SysUser user = new SysUser();
        user.setUsername("admin_"+tenantId);
        user.setPassword("123456");
        user.setRealname("admin_"+tenantId);
        user.setWorkNo("1");
        user.setRelTenantIds(tenantId+"");
        user.setUserIdentity(1);
        user.setPhone("13667651146");
        user.setActivitiSync(1);


        user.setCreateTime(new Date());//设置创建时间
        String salt = oConvertUtils.randomGen(8);
        user.setSalt(salt);
        String passwordEncode = PasswordUtil.encrypt(user.getUsername(), user.getPassword(), salt);
        user.setPassword(passwordEncode);
        user.setStatus(1);
        user.setDelFlag(CommonConstant.DEL_FLAG_0);
        //用户表字段org_code不能在这里设置他的值
        user.setOrgCode(null);
        // 保存用户走一个service 保证事务
        userService.saveUser(user, roleId, "");
        baseCommonService.addLog("添加用户，username： " +user.getUsername() ,CommonConstant.LOG_TYPE_2, 2);
    }

    /**
     * 保存超级租户的菜单到其他租户，
     * 并且使用md5解决父id关联问题
     * @param ls
     * @param tenantId
     * @return
     */
    @Override
    public Collection<String> setPermissionTenant(List<SysPermission> ls, int tenantId){
        // 循环两次 第一次设置ID和tenantId 第二次设置pid
        Map<String, String> map = new HashMap<>();
        for(SysPermission p: ls){
            String oldId = p.getId();
            String newId = Md5Util.md5Encode(oldId+"-"+tenantId,"utf-8");
            map.putIfAbsent(oldId, newId);
            p.setId(newId);
            p.setTenantId(tenantId);
            p.setCreateBy(null);
            p.setCreateTime(null);
            p.setUpdateBy(null);
            p.setUpdateTime(null);
            p.setReferenceId(oldId);
        }
        for(SysPermission p: ls){
            String oldPid = p.getParentId();
            if(oConvertUtils.isNotEmpty(oldPid)){
                String newPid = map.get(oldPid);
                if(oConvertUtils.isNotEmpty(newPid)){
                    p.setParentId(newPid);
                }else{
                    p.setParentId(Md5Util.md5Encode(oldPid+"-"+tenantId,"utf-8"));
                }
            }
        }
        return map.values();
    }
}
